import requests
import logging
import os
import random
import json
import time
from urllib.parse import quote

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)


csrf = "" # 填入你的csrf
outer_sid = "20ERAmwloghvnbj00" # 简单版10题随机的这个字符串为 "20ERAmwloghvnm800"
headers = {
    'Host': 'api.bilibili.com',
    'user-agent': 'Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/87.0.4280.101 Safari/537.36',
    'origin': 'https://www.bilibili.com',
    'Connection': 'keep-alive',
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
    'x-requested-with': 'tv.danmaku.bilibili',
    'sec-fetch-site': 'same-site',
    'sec-fetch-mode': 'cors',
    'sec-fetch-dest': 'empty',
    'referer': 'https://www.bilibili.com/blackboard/era/znAqbhtqqklB4mtv.html',
    'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
    'cookie': '''buvid3=...; b_nut=...; DedeUserID=...; ...''' # 填入你的cookie
}

def start_answer():
    url =  f"https://api.bilibili.com/x/activity_components/new_question/start_answer?csrf={csrf}"
    payload = {"outer_sid": outer_sid}
    try:
        response = requests.post(url, headers=headers, json=payload)
    except Exception as e:
        logger.error("尝试开始回答时出现请求错误: " + str(e))
        os._exit(-1)
    if response.status_code == 200:
        data = response.json()
        if data.get("code") == 0 and "data" in data:
            data = data["data"]
            logger.debug("开始回答成功，data: " + str(data))
            return data
        else:
            logger.error("尝试开始回答时出现错误，返回数据: " + str(data))
            os._exit(-1)
    else:
        logger.error("尝试开始回答时出现错误，状态码: " + str(response.status_code))
        os._exit(-1)

def get_prompt(pool, index):
    pool = quote(pool, safe='')
    url = f"https://api.bilibili.com/x/activity_components/new_question/get_prompt?outer_sid={outer_sid}&pool={pool}&index={index}"
    try:
        response = requests.get(url, headers=headers)
    except Exception as e:
        logger.error("尝试获取题目时出现请求错误: " + str(e))
        os._exit(-1)
    prompt = {}
    if response.status_code == 200:
        data = response.json()
        if data.get("code") == 0 and "data" in data:
            prompt['question'] = data["data"]["question"]
            prompt['prompt_id'] = data["data"]["prompt_id"]
            prompt['opt_list'] = data["data"]["opt_list"]
            logger.debug("pool: " + pool + ", index: " + str(index) + ", 获取的题目: " + str(prompt))
            return prompt
        else:
            logger.error("尝试获取题目时出现错误，返回数据: " + str(data))
            os._exit(-1)
    else:
        logger.error("尝试获取题目时出现错误，状态码: " + str(response.status_code))
        os._exit(-1)


def submit_answer(pool, index, selected_options):
    url = f"https://api.bilibili.com/x/activity_components/new_question/submit_answer?csrf={csrf}"
    payload = {
        "outer_sid": outer_sid,
        "pool": pool,
        "index": index,
        "selected_options": [selected_options]
    }
    try:
        response = requests.post(url, headers=headers, json=payload)
    except Exception as e:
        logger.error("尝试回答题目时出现请求错误: " + str(e))
        os._exit(-1)
    result = {}
    if response.status_code == 200:
        data = response.json()
        if data.get("code") == 0 and "data" in data:
            logger.debug(str(data))
            result['result'] = data['data']['result']
            result['answers'] = data['data']['answers']
            result['next_pool'] = data['data']['pool']
            logger.debug("pool: " + pool + ", index: " + str(index) + ", selected_options: " + selected_options + ", 结果: " + str(result))
            return result
        else:
            logger.error("尝试回答题目出现错误，返回数据: " + str(data))
            os._exit(-1)
    else:
        logger.error("尝试回答题目出现错误，状态码: " + str(response.status_code))
        os._exit(-1)

def get_result(last_pool):
    last_pool = quote(last_pool, safe='')
    url = f"https://api.bilibili.com/x/activity_components/new_question/get_result?outer_sid={outer_sid}&pool={last_pool}"
    try:
        response = requests.get(url, headers=headers)
    except Exception as e:
        logger.error("尝试获取结果时出现请求错误: " + str(e))
        os._exit(-1)
    result = {}
    if response.status_code == 200:
        data = response.json()
        if data.get("code") == 0 and "data" in data:
            result = data['data']
            logger.debug("last_pool: " + last_pool + ", 结果: " + str(result))
            return result
        else:
            logger.error("尝试获取结果出现错误，返回信息: " + str(data))
            os._exit(-1)
    else:
        logger.error("尝试获取结果出现错误，状态码: " + str(response.status_code))
        os._exit(-1)

#logger.info("question_num: " + str(question_num()))
first_data = start_answer()
total = first_data['total']
pool = first_data['pool']
last_pool = ""

with open("answers.json", 'r', encoding='utf-8') as file:
    answers = json.load(file)


for i in range(total):
    prompt = get_prompt(pool, i)
    logger.info(str(i + 1) + "/" + str(total))
    logger.info(prompt['question'])
    logger.info(prompt['opt_list'])
    #logger.info("请输入你的答案(序号)")
    #ans = int(input())
    if prompt['question'] in answers:
        logger.info("已找到正确答案: " + str(answers[prompt['question']]))
        answers_ = answers.get(prompt['question'], [])
        ans = next(i for i, opt in enumerate(prompt['opt_list']) if opt['content'] in answers_)
    else:
        ans = random.randint(0, len(prompt['opt_list']) - 1)
        logger.info("未找到正确答案, 进行随机提交: " + prompt['opt_list'][ans]['content'])
    logger.info("对应选项id: " + prompt['opt_list'][ans]['id'])
    result = submit_answer(pool, i, prompt['opt_list'][ans]['id'])
    logger.info("回答正确" if result['result'] else "回答错误" + ", 正确答案id:" + str(result['answers']))
    answers[prompt['question']] = [option['content'] for option in prompt['opt_list'] if option['id'] in result['answers']]
    pool = result['next_pool']
    if i == total - 1:
        last_pool = pool

with open("answers.json", 'w', encoding='utf-8') as file:
    json.dump(answers, file, ensure_ascii=False, indent=4)
time.sleep(2)
result = get_result(last_pool)
logger.info("结果: ")
logger.info("答对题数: " + str(result['count']))
logger.info("获得分数: " + str(result['score']))
logger.info("用户昵称: " + str(result['nickname']))
logger.info("当前等级(0为等级未改变): " + str(result['level']))
logger.info("当前标志: " + str(result['icon']))
logger.info("提示: " + str(result['tips']))